// SPDX-License-Identifier: GPL-2.0-or-later

#if !defined(WIN32)
#include <unistd.h>
#endif

#if defined(__linux__) || defined(__GLIBC__)
#include <QLocale>
#endif

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>

#include <QDesktopServices>
#include <QDir>
#include <QFontComboBox>
#include <QFontDialog>
#include <QInputDialog>
#include <QKeySequence>
#include <QList>
#include <QMdiArea>
#include <QMdiSubWindow>
#include <QMenuBar>
#include <QMessageBox>
#include <QSignalMapper>
#include <QStatusBar>
#include <QStyleFactory>
#include <QTime>
#include <QSizePolicy>
#include <QTimer>
#include <QToolBar>
#include <QTranslator>
#include <QWindowStateChangeEvent>

#include "aboutdialog.h"
#include "addrdialog.h"
#include "common.h"
#include "keydialog.h"
#include "prefdialog.h"
#include "fqterm.h"

#include "fqterm_path.h"
#include "fqterm_config.h"
#include "fqterm_frame.h"
#include "fqterm_param.h"
#include "fqterm_session.h"
#include "fqterm_screen.h"
#include "fqterm_time_label.h"
#include "fqterm_tool_button.h"
#include "fqterm_window.h"
#include "fqterm_wndmgr.h"

#ifdef IMAGE_USE_PICFLOW
#include "imageviewer.h"
#else
#include "imageviewer_origin.h"
#endif

#include "quickdialog.h"
#include "statusBar.h"
#include "sitemanager.h"
#include "fqterm_shortcuthelper.h"
#include "shortcutdialog.h"
#include "schemadialog.h"
#include "fqterm_ip_location.h"
#include "iplookup.h"
#include "defineescape.h"
#include "uaocodec.h"

#include "connect_info.h"

#ifdef USE_DOTNET_STYLE
#include "dotnetstyle.h"
#endif //USE_DOTNET_STYLE

#ifdef USE_GLOBAL_HOTKEY
#include "qxtglobalshortcut.h"
#endif //USE_GLOBAL_HOTKEY

#ifdef HAVE_PYTHON
#include <Python.h>
#include "fqterm_python.h"
#endif //HAVE_PYTHON

namespace FQTerm {


const QString FQTermFrame::qmPrefix[FQTermFrame::translatedModule] = {"fqterm_", "ui_", "protocol_", "common_"};
const QString FQTermFrame::qmPostfix = ".qm";

//constructor
FQTermFrame::FQTermFrame()
	: QMainWindow(0), 
	  tray_(0),
	  trayMenu_(0), 
	  shortcutHelper_(0)
{
	setAttribute(Qt::WA_DeleteOnClose);

	uaoCodec_ = new UAOCodec;
  
	config_ = new FQTermConfig(getPath(USER_CONFIG) + "fqterm.cfg");

	initTranslator();
	shortcutHelper_ = new FQTermShortcutHelper(config_, this);

#ifdef IMAGE_USE_PICFLOW
	imageViewer_ = new FQTermImageFlow(config_, NULL, Qt::Window);
#else
	imageViewer_ = new FQTermImageOrigin(config_, NULL, Qt::Window);
#endif


	//create the window manager to deal with the window-tab-icon pairs
	windowManager_ = new FQTermWndMgr(this);
	setCentralWidget(windowManager_);

	//set menubar
	addMainMenu();
    FQ_VERIFY(connect(this, SIGNAL(changeLanguage()), this, SLOT(recreateMenu())));

	//initialize all settings
	//This should be done before add main tool, since some status of tool will depend on setting
	iniSetting();
	FQTermConfig* conf = new FQTermConfig(getPath(USER_CONFIG) + "address.cfg");
	checkHelpExists(conf);
	delete conf;
	//setup toolbar
	addMainTool();

	// add the custom defined key
	// and load toolbar position
    //updateKeyToolBar();
	loadToolBarPosition();
	enableMenuToolBar(false);

	// FIXME: !!!create a horizonal layout to hold the tabbar,the reason
	//of why not put the tabbar directly on the status bar is when no
	//tab in the tabbar,the statusbar display a horizonal line,ugly.
	//perhaps there is some function in statusbar to solve this.
	QWidget *hb = new QWidget(statusBar());
	hb->setObjectName("taskbar");
	QHBoxLayout *hbLayout = new QHBoxLayout(hb);
	hbLayout->setMargin(0);
	hbLayout->setObjectName("tasklayout");
	statusBar()->addWidget(hb);
	//create a tabbar in the hbox
	hbLayout->addWidget(windowManager_->tabBar());

	windowMapper_ = new QSignalMapper(this);
    FQ_VERIFY(connect(windowMapper_, SIGNAL(mapped(int)), windowManager_, SLOT(activateTheWindow(int))));
	initAdditionalActions();

	//create a progress bar to notify the download process
	statusBar_ = new FQTerm::StatusBar(statusBar(), "mainStatusBar");
	statusBar()->addWidget(statusBar_, 0);

	installEventFilter(this);
}

//destructor
FQTermFrame::~FQTermFrame()
{
	clearTranslator();
	delete imageViewer_;
	delete shortcutHelper_;
	delete config_;
	// should not delete yourself!!
	// http://qt-project.org/doc/qt-5/qtextcodec.html#dtor.QTextCodec
	//  delete uaoCodec_;
	delete windowManager_;
	FQTermIPLocation::Destroy();
}

//initialize setting from fqterm.cfg
void FQTermFrame::iniSetting() {
	QString strTmp;

	strTmp = config_->getItemValue("global", "fullscreen");
	if (strTmp == "1") {
		getAction(FQTermShortcutHelper::FULLSCREEN)->setChecked(true);
		showFullScreen();
	} else {
		//window size
		strTmp = config_->getItemValue("global", "max");
		if (strTmp == "1") {
			showMaximized();
		} else {
			QString size = config_->getItemValue("global", "size");
			if (size != "") {
				int x, y, cx, cy;
				sscanf(size.toLatin1(), "%d %d %d %d", &x, &y, &cx, &cy);
				resize(QSize(cx, cy));
				move(QPoint(x, y));
			}
		}
	}

	theme_ = config_->getItemValue("global", "theme");
	QStyle *style;
    style = QStyleFactory::create(theme_);
	if (style) {
		qApp->setStyle(style);
	}

	//language
	updateLanguageMenu();

	//TODO: 
	getAction(FQTermShortcutHelper::COLORCTL_NO)->setChecked(true);
	FQTermPref::getInstance()->escapeString_ = config_->getItemValue("global", "escstr");
	if (FQTermPref::getInstance()->escapeString_ == "") {
		getAction(FQTermShortcutHelper::COLORCTL_NO)->setChecked(true);
		getAction(FQTermShortcutHelper::COLORCTL_OLD_CUSTOM)->setVisible(false);
	} else if (FQTermPref::getInstance()->escapeString_ == "^[^[[") {
		getAction(FQTermShortcutHelper::COLORCTL_SMTH)->setChecked(true);
		getAction(FQTermShortcutHelper::COLORCTL_OLD_CUSTOM)->setVisible(false);
	} else if (FQTermPref::getInstance()->escapeString_ == "^u[") {
		getAction(FQTermShortcutHelper::COLORCTL_PTT)->setChecked(true);
		getAction(FQTermShortcutHelper::COLORCTL_OLD_CUSTOM)->setVisible(false);
	} else {
		QAction *pAction = getAction(FQTermShortcutHelper::COLORCTL_OLD_CUSTOM);
		QString transStrEsc;
		transEscapeStr(transStrEsc, FQTermPref::getInstance()->escapeString_);
		pAction->setText(transStrEsc);
		pAction->setVisible(true);
		pAction->setChecked(true);
	}

	strTmp = config_->getItemValue("global", "vscrollpos");
	if (strTmp == "0") {
		FQTermPref::getInstance()->termScrollBarPosition_ = 0;
		getAction(FQTermShortcutHelper::SCROLLBAR_HIDDEN)->setChecked(true);
	} else if (strTmp == "1") {
		FQTermPref::getInstance()->termScrollBarPosition_ = 1;
		getAction(FQTermShortcutHelper::SCROLLBAR_LEFT)->setChecked(true);
	} else {
		FQTermPref::getInstance()->termScrollBarPosition_ = 2;
		getAction(FQTermShortcutHelper::SCROLLBAR_RIGHT)->setChecked(true);
	}
	strTmp = config_->getItemValue("global", "switchbar");
	isTabBarShown_ = (strTmp != "0");
	getAction(FQTermShortcutHelper::SWITCHBAR)->setChecked(isTabBarShown_);
    /*if (isTabBarShown_) {
		statusBar()->show();
	} else {
		statusBar()->hide();
    }*/
    statusBar()->hide();

	//read sub-window setting.
	strTmp = config_->getItemValue("global", "subwindowmax");
	windowManager_->setSubWindowMax((strTmp != "0"));


	strTmp = config_->getItemValue("global", "subwindowsize");
	if (strTmp != "") {
		//FIXME: In case of sub window size not saved properly.
		int w, h;
		sscanf(strTmp.toLatin1(), "%d %d", &w, &h);
		windowManager_->setSubWindowSize(QSize(w, h));
	} else {
		//Magic Number. Initialize Window Size to Avoid Errors.
		windowManager_->setSubWindowSize(QSize(640, 480));
	}

	FQTermPref::getInstance()->isBossColor_ = false;

	loadPref();

	setUseDock(FQTermPref::getInstance()->openMinimizeToTray_);

	if (FQTermPref::getInstance()->useStyleSheet_) {
		loadStyleSheetFromFile(FQTermPref::getInstance()->styleSheetFile_);
	}
}

void FQTermFrame::loadPref() {
	QString strTmp;
  
	strTmp = config_->getItemValue("preference", "displayoffset");
	FQTermPref::getInstance()->displayOffset_ = strTmp.toInt();
	strTmp = config_->getItemValue("preference", "vsetting");
	FQTermPref::getInstance()->vsetting_ = strTmp.toInt();
	strTmp = config_->getItemValue("preference", "xim");
	FQTermPref::getInstance()->imeEncodingID_ = strTmp.toInt();
	strTmp = config_->getItemValue("preference", "wordwrap");
	FQTermPref::getInstance()->widthToWrapWord_ = strTmp.toInt();
	//  strTmp = conf->getItemValue("preference", "smartww");
	//  m_pref.bSmartWW = (strTmp != "0");
	strTmp = config_->getItemValue("preference", "wheel");
	FQTermPref::getInstance()->isWheelSupported_ = (strTmp != "0");
	strTmp = config_->getItemValue("preference", "url");
	FQTermPref::getInstance()->openUrlCheck_ = (strTmp != "0");
	//  strTmp = conf->getItemValue("preference", "logmsg");
	//  m_pref.bLogMsg = (strTmp != "0");
	strTmp = config_->getItemValue("preference", "blinktab");
	FQTermPref::getInstance()->openTabBlinking_ = (strTmp != "0");
	strTmp = config_->getItemValue("preference", "warn");
	FQTermPref::getInstance()->openWarnOnClose_ = (strTmp != "0");
	strTmp = config_->getItemValue("preference", "beep");
	FQTermPref::getInstance()->openBeep_ = strTmp.toInt();
	FQTermPref::getInstance()->beepSoundFileName_ = config_->getItemValue("preference", "wavefile");
	strTmp = config_->getItemValue("preference", "http");
	FQTermPref::getInstance()->httpBrowser_ = strTmp;
	//  m_pref.strHttp = strTmp;
	strTmp = config_->getItemValue("preference", "antialias");
	FQTermPref::getInstance()->openAntiAlias_ = (strTmp != "0");
	strTmp = config_->getItemValue("preference", "enq");
	FQTermPref::getInstance()->replyENQ_ = (strTmp != "0");
	strTmp = config_->getItemValue("preference", "tray");
	if (strTmp.isEmpty()) {
#if defined(__APPLE__) || defined(__linux__) || defined(__GLIBC__)
		FQTermPref::getInstance()->openMinimizeToTray_ = false;
#else
		FQTermPref::getInstance()->openMinimizeToTray_ = true;    
#endif
	} else {
		FQTermPref::getInstance()->openMinimizeToTray_ = (strTmp != "0");
	}
	strTmp = config_->getItemValue("preference", "playmethod");
	FQTermPref::getInstance()->beepMethodID_ = strTmp.toInt();
	strTmp = config_->getItemValue("preference", "externalplayer");
	FQTermPref::getInstance()->beepPlayerName_ = strTmp;

	strTmp = config_->getItemValue("preference", "clearpool");
	FQTermPref::getInstance()->needClearZmodemPoolOnClose_ = (strTmp == "1");
	strTmp = config_->getItemValue("preference", "pool");
	FQTermPref::getInstance()->poolDir_ = strTmp.isEmpty() ?
		getPath(USER_CONFIG) + "pool/": strTmp;
	if (FQTermPref::getInstance()->poolDir_.right(1) != "/") {
		FQTermPref::getInstance()->poolDir_.append('/');
	}
	strTmp = config_->getItemValue("preference", "zmodem");
	FQTermPref::getInstance()->zmodemDir_ = strTmp.isEmpty() ?
		getPath(USER_CONFIG) + "zmodem/": strTmp;
	if (FQTermPref::getInstance()->zmodemDir_.right(1) != "/") {
		FQTermPref::getInstance()->zmodemDir_.append('/');
	}
	strTmp = config_->getItemValue("preference", "image");
	FQTermPref::getInstance()->imageViewerName_ = strTmp;
	strTmp = config_->getItemValue("preference", "qssfile");
	FQTermPref::getInstance()->styleSheetFile_ = strTmp;
	FQTermPref::getInstance()->useStyleSheet_ = !strTmp.isEmpty();

	strTmp = config_->getItemValue("preference", "editor");
	FQTermPref::getInstance()->externalEditor_ = strTmp;

	//FIXME: duplicated strings.
	strTmp = config_->getItemValue("preference", "searchengine");
    if (strTmp == "baidu") {
		getAction(FQTermShortcutHelper::SEARCH_BAIDU)->setChecked(true);
    } else if (strTmp == "custom") {
		getAction(FQTermShortcutHelper::SEARCH_CUSTOM)->setChecked(true);
	} else {
		getAction(FQTermShortcutHelper::SEARCH_GOOGLE)->setChecked(true);
        strTmp = "baidu";
	}
	FQTermPref::getInstance()->searchEngine_ = strTmp;

	strTmp = config_->getItemValue("preference", "editorarg");
	FQTermPref::getInstance()->externalEditorArg_ = strTmp;
 
	strTmp = config_->getItemValue("preference", "asciienhance");
	FQTermPref::getInstance()->isAnsciiEnhance_ = (strTmp == "1");
}

//save current setting to fqterm.cfg
void FQTermFrame::saveSetting() {
	QString strTmp;
	//save font
	config_->setItemValue("global", "font", qApp->font().family());
	strTmp.setNum(QFontInfo(qApp->font()).pointSize());
	config_->setItemValue("global", "pointsize", strTmp);
	strTmp.setNum(QFontInfo(qApp->font()).pixelSize());
	config_->setItemValue("global", "pixelsize", strTmp);

	//save window position and size
	if (isMaximized()) {
		config_->setItemValue("global", "max", "1");
	} else {
		strTmp = QString("%1 %2 %3 %4").arg(x()).arg(y()).arg(width()).arg(height());
		// 		cstrTmp.sprintf("%d %d %d %d",x(),y(),width(),height());
		config_->setItemValue("global", "size", strTmp);
		config_->setItemValue("global", "max", "0");
	}

	if (windowState() & Qt::WindowFullScreen) {
		config_->setItemValue("global", "fullscreen", "1");
	} else {
		config_->setItemValue("global", "fullscreen", "0");
	}

	// cstrTmp.setNum(theme);
	config_->setItemValue("global", "theme", theme_);

	config_->setItemValue("global", "escstr", FQTermPref::getInstance()->escapeString_);

	strTmp.setNum(FQTermPref::getInstance()->termScrollBarPosition_);
	config_->setItemValue("global", "vscrollpos", strTmp);

	config_->setItemValue("global", "switchbar", isTabBarShown_ ? "1" : "0");

	//save subwindow setting
	config_->setItemValue("global", "subwindowmax", windowManager_->getSubWindowMax() ? "1" : "0");
	int w = windowManager_->getSubWindowSize().width();
	int h = windowManager_->getSubWindowSize().height();

	strTmp = QString("%1 %2").arg(w).arg(h);
	config_->setItemValue("global", "subwindowsize", strTmp);

	//Save toolbarstate.
	QByteArray state = saveState().toHex();
	strTmp = QString(state);
	config_->setItemValue("global", "toolbarstate", strTmp);

	config_->save(getPath(USER_CONFIG) + "fqterm.cfg");
}

void FQTermFrame::initAdditionalActions()
{
	QString opt(tr("Alt"));  

	for (int i = 1; i <= 10; ++i) {
		QAction *idAction = new QAction(this);
		QString shortcut(opt);
		shortcut += "+" + QString("").setNum(i % 10);
		idAction->setShortcut(shortcut);
		connect(idAction, SIGNAL(triggered()), windowMapper_, SLOT(map()));
		windowMapper_->setMapping(idAction, i - 1);
		addAction(idAction);
	}

	FQTERM_ADDACTION(windowManager_, NEXTWINDOW, windowManager_, activateNextWindow);
	FQTERM_ADDACTION(windowManager_, PREVWINDOW, windowManager_, activatePrevWindow);

}

//addressbook
void FQTermFrame::addressBook()
{
    siteDialog siteManager(this );
	if (siteManager.exec() == 1) {
		newWindow(siteManager.currentParameter(), siteManager.currentSiteIndex());
	}
}

//quicklogin
void FQTermFrame::quickLogin()
{
	quickDialog quick(config_, this);
	FQTermConfig *pConf = new FQTermConfig(getPath(USER_CONFIG) + "address.cfg");

	loadAddress(pConf, -1, quick.param_);
	delete pConf;

	if (quick.exec() == 1) {
		newWindow(quick.param_);
    }
}

void FQTermFrame::exitFQTerm()
{
	if (!clearUp()) return;
	deleteLater();
}

void FQTermFrame::newWindow(const FQTermParam &param, int index) {
	QIcon *icon = new QIcon(QPixmap(getPath(RESOURCE) + "pic/tabpad.png"));
	FQTermWindow* window = windowManager_->newWindow(param, config_, icon, index);

	updateFontCombo();
	FQ_VERIFY(connect(window->getScreen(), SIGNAL(termFontChange(bool,QFont)), this, SLOT(termFontChange(bool,QFont))));

	window->connectHost();
}


void FQTermFrame::aboutFQTerm() {
	aboutDialog about(this);
	about.exec();
}

//slot Help->Homepage
void FQTermFrame::homepage()
{
	/*const QString &httpBrowser = FQTermPref::getInstance()->httpBrowser_;
	const QString homeUrl = "https://www.rockemb.com";

	if (httpBrowser.isNull() || httpBrowser.isEmpty()) {
		QDesktopServices::openUrl(homeUrl);
	} else {
		runProgram(httpBrowser, homeUrl);
	}*/
}

//slot Windows menu aboutToShow
void FQTermFrame::windowsMenuAboutToShow()
{
	menuWindows_->clear();
	FQTERM_ADDACTION(menuWindows_, CASCADEWINDOWS, windowManager_, cascade);
	FQTERM_ADDACTION(menuWindows_, TILEWINDOWS, windowManager_, tile);
	if (windowManager_->count() == 0) {
		getAction(FQTermShortcutHelper::CASCADEWINDOWS)->setEnabled(false);
		getAction(FQTermShortcutHelper::TILEWINDOWS)->setEnabled(false);
	}
	menuWindows_->addSeparator();

#ifdef Q_OS_MACX
	// used to dock the program
	if (isHidden()) {
		menuWindows_->addAction(tr("Main Window"), this, SLOT(trayShow()));
	}
#endif

	for (int i = 0; i < int(windowManager_->count()); ++i) {
		QAction *idAction = menuWindows_->addAction(windowManager_->subWindowList().at(i)->windowTitle());
		idAction->setCheckable(true);
		idAction->setChecked(windowManager_->activeWindow() == windowManager_->nthWindow(i));
		connect(idAction, SIGNAL(triggered()), windowMapper_, SLOT(map()));
		windowMapper_->setMapping(idAction, i);
	}
}

void FQTermFrame::reloadConfig() {
	config_->load(getPath(USER_CONFIG) + "fqterm.cfg");
}

void FQTermFrame::popupConnectMenu() {
	menuConnect_->clear();
	menuConnect_->addAction(tr("Quick Login"), this, SLOT(quickLogin()));
	menuConnect_->addSeparator();
  
	FQTermConfig conf(getPath(USER_CONFIG) + "address.cfg");

	QStringList listName;
	loadNameList(&conf, listName);

	for (int i = 0; i < listName.count(); i++) {
        QAction *idAction = menuConnect_->addAction(listName[i], this, SLOT(connectMenuActivated()));
		idAction->setData(i);
		if (i < 10) {

			QString shortCut(tr("Ctrl+Alt"));
			shortCut += "+" + QString("").setNum((i + 1)% 10);
			idAction->setShortcut(shortCut);
		}
	}

	int lastIndex = config_->getItemValue("global", "lastaddrindex").toInt();
	if (lastIndex < 0 || lastIndex >= listName.count())
		lastIndex = 0;
	if (listName.count() > 0)
	{    
		menuConnect_->addSeparator();
		QAction *idAction = menuConnect_->addAction(listName[lastIndex], this, SLOT
							    (connectMenuActivated()));
		idAction->setData(LAST_ADDRESS_INDEX);
#ifdef __APPLE__
		QString shortCut(tr("Ctrl+Meta"));
#else
		QString shortCut(tr("Ctrl+Alt"));
#endif
		shortCut += "+" + QString("-");
		idAction->setShortcut(shortCut);

	}
}

void FQTermFrame::connectMenuActivated()
{
	FQTermConfig *pConf = new FQTermConfig(getPath(USER_CONFIG) + "address.cfg");
	int id = static_cast < QAction * > (sender())->data().toInt();
	if (id == LAST_ADDRESS_INDEX)
	{
		id = config_->getItemValue("global", "lastaddrindex").toInt();
	}
  
	FQTermParam param;

	// FIXME: don't know the relation with id and param set by setItemParameter
	if (loadAddress(pConf, id, param)) {
		newWindow(param, id);
	}
	delete pConf;
}


bool FQTermFrame::eventFilter(QObject *o, QEvent *e)
{
	return false;
}

void FQTermFrame::closeEvent(QCloseEvent *clse)
{
	if (FQTermPref::getInstance()->openMinimizeToTray_ &&
	    windowManager_->count() > 0) {
		trayHide();
		clse->ignore();
		return ;
	}
	if (!clearUp())
	{
		clse->ignore();
		return;
	}

	clse->accept();

	deleteLater();
}

void FQTermFrame::langEnglish()
{
	installTranslator("en_US");
}

void FQTermFrame::disconnect()
{
	FQTermWindow* aw = windowManager_->activeWindow();
	if (aw) {
		aw->disconnect();
	}
}

static QString ssh2_info(conn_info_t *info)
{
	QString txt;
	txt.append("\nhost key (SHA256): ");
	const char *tab = "0123456789ABCDEF";
	for (int i=0; i<32; i++) {
		unsigned char b = info->ssh_proto_info.hash[i];
		char hex[4] = { tab[(b>>4)], tab[b&0xf], ':', 0 };
		if (i==31)
			hex[2] = 0;
		txt.append(hex);
	}
	txt.append(QString("\ncipher(c2s): %1\ncipher(s2c): %2")
		   .arg(info->ssh_proto_info.c2s_cipher)
		   .arg(info->ssh_proto_info.s2c_cipher));
	if (info->ssh_proto_info.c2s_mac) {
		txt.append(QString("\nMAC(c2s): %1")
			   .arg(info->ssh_proto_info.c2s_mac));
	}
	if (info->ssh_proto_info.s2c_mac) {
		txt.append(QString("\nMAC(s2c): %1")
			   .arg(info->ssh_proto_info.s2c_mac));
	}
	if (info->ssh_proto_info.key_matches)
		txt.append("\nkey matches");
	else
		txt.append("\nkey mismatch!");

	return txt;
}

void FQTermFrame::conn_info()
{
	FQTermSession *sess = windowManager_->activeWindow()->getSession();
	conn_info_t *info = sess->connectionInfo();
	QString txt;
	switch (info->proto) {
	case PROTO_TELNET:
		txt = "protocol: Telnet";
		txt.append(QString("\nHost: %1\nPort: %2")
			   .arg(info->hostname).arg(info->port));
		break;
	case PROTO_LOCAL:
		txt = "protocol: Local";
		break;
	case PROTO_SSH:
		txt = QString("protocol: SSH %1")
			.arg(info->ssh_proto_info.proto_version);
		txt.append(QString("\nHost: %1\nPort: %2")
			   .arg(info->hostname).arg(info->port));
		if (info->ssh_proto_info.proto_version == 2)
			txt.append(ssh2_info(info));
		break;
	}
    QMessageBox b(QMessageBox::Information, "Connection Information",txt, QMessageBox::Ok, this);
	b.exec();
}

void FQTermFrame::copy()
{
	windowManager_->activeWindow()->copy();
}

void FQTermFrame::paste()
{
	windowManager_->activeWindow()->paste();
}

void FQTermFrame::searchIt()
{
	windowManager_->activeWindow()->searchIt();
}

void FQTermFrame::shareIt()
{
	windowManager_->activeWindow()->shareIt();
}

void FQTermFrame::externalEditor() {
	windowManager_->activeWindow()->externalEditor();
}

void FQTermFrame::fastPost() {
	windowManager_->activeWindow()->fastPost();
}

void FQTermFrame::copyRect() {
	windowManager_->activeWindow()->getSession()->param().isRectSelect_
		= !windowManager_->activeWindow()->getSession()->param().isRectSelect_;

	getAction(FQTermShortcutHelper::RECTANGLESELECTION)->setChecked(
		windowManager_->activeWindow()->getSession()->param().isRectSelect_);
}

void FQTermFrame::copyColor() {
	windowManager_->activeWindow()->getSession()->param().isColorCopy_
		= !windowManager_->activeWindow()->getSession()->param().isColorCopy_;

	getAction(FQTermShortcutHelper::COPYWITHCOLOR)->setChecked(
		windowManager_->activeWindow()->getSession()->param().isColorCopy_);
}

void FQTermFrame::copyArticle() {
	windowManager_->activeWindow()->copyArticle();
}

void FQTermFrame::autoCopy() {
	windowManager_->activeWindow()->getSession()->param().isAutoCopy_
		= !windowManager_->activeWindow()->getSession()->param().isAutoCopy_;

	getAction(FQTermShortcutHelper::AUTOCOPYSELECTION)->setChecked(
		windowManager_->activeWindow()->getSession()->param().isAutoCopy_);
}

void FQTermFrame::wordWrap() {
	windowManager_->activeWindow()->getSession()->param().isAutoWrap_
		= !windowManager_->activeWindow()->getSession()->param().isAutoWrap_;

	getAction(FQTermShortcutHelper::PASTEWORDWRAP)->setChecked(
		windowManager_->activeWindow()->getSession()->param().isAutoWrap_);
}

void FQTermFrame::noEsc() {
	FQTermPref::getInstance()->escapeString_ = "";
	getAction(FQTermShortcutHelper::COLORCTL_NO)->setChecked(true);
	getAction(FQTermShortcutHelper::COLORCTL_OLD_CUSTOM)->setVisible(false);
}

void FQTermFrame::escEsc() {
	FQTermPref::getInstance()->escapeString_ = "^[^[[";
	getAction(FQTermShortcutHelper::COLORCTL_SMTH)->setChecked(true);
	getAction(FQTermShortcutHelper::COLORCTL_OLD_CUSTOM)->setVisible(false);
}

void FQTermFrame::uEsc() {
	FQTermPref::getInstance()->escapeString_ = "^u[";
	getAction(FQTermShortcutHelper::COLORCTL_PTT)->setChecked(true);
	getAction(FQTermShortcutHelper::COLORCTL_OLD_CUSTOM)->setVisible(false);
}

void FQTermFrame::oldCustomEsc() {
}

void FQTermFrame::customEsc() {
	QString strEsc(FQTermPref::getInstance()->escapeString_);
	DefineEscapeDialog defineEscapeDialog_(strEsc, this);
	if (defineEscapeDialog_.exec() == 1)
	{
		FQTermPref::getInstance()->escapeString_ = strEsc;
		QAction *pAction = getAction(FQTermShortcutHelper::COLORCTL_OLD_CUSTOM);
		if (strEsc != QString("") && strEsc != QString("^[^[[") && strEsc != QString("^u["))
		{
			QString transStrEsc;
			transEscapeStr(transStrEsc, strEsc);
			pAction->setText(transStrEsc);
			pAction->setVisible(true);
			pAction->setChecked(true);
        }else{
			pAction->setVisible(false);
		}
	}
}

bool FQTermFrame::isDelimiterExistedBefore(const QString& str, const std::vector<QString>& existingDelimiters) {
    for (auto cit = existingDelimiters.begin(); cit != existingDelimiters.end(); ++cit){
        if (str.right(cit->length()) == *cit){
			return true;
		}
	}
	return false;
}

int FQTermFrame::isDelimiterExistedAfter(const QString& str, const std::vector<QString>& existingDelimiters)
{
    for (std::vector<QString>::const_iterator cit = existingDelimiters.begin(); cit != existingDelimiters.end(); ++cit){
        if (str.left(cit->length()) == *cit){
			return cit->length();
		}
	}
	return 0;
}

bool FQTermFrame::uppercaseCharFollowingCtrl(QString& str,int& i, const QString& after)
{
    if (after == QString("Ctrl") && str[i] > 'a' - 1 && str[i] < 'z' - 1){
		str[i] = str[i].toUpper();
		++i;
		return true;
    }
    return false;
}

void FQTermFrame::replaceEscapeString(QString& str, const QString& before, const QString& after, const QString& delimiter,
                                      const std::vector<QString> *existingDelimiters /* = NULL */) {
	bool preMatched = false;
	int i = 0;
    while (i < str.length()){
		bool matched = true;
        for (int j = 0; j < before.length(); ++j){
            if (str[i + j] != before[j]){
				matched = false;
				break;
			}
        }// end of for
        if (matched){
			if (i == 0)
			{
				// the matched string is the head of the string
				str = after + delimiter + str.right(str.length() - before.length());
				i = after.length() + delimiter.length();
				bool changed = uppercaseCharFollowingCtrl(str, i, after);
				preMatched = !changed;
            }else if (i == str.length() - before.length()){
				// the matched string is the tail of the string
                if (existingDelimiters != NULL && isDelimiterExistedBefore(str.left(i), *existingDelimiters)){
					preMatched = true;
				}

                if (preMatched){
					str = str.left(i) + after;
                }else{
					str = str.left(i) + delimiter + after;
				}
				break;
            }else{
				// the matched string is at the middle of the string
				if (existingDelimiters != NULL &&
				    isDelimiterExistedBefore(str.left(i), *existingDelimiters))
				{
					preMatched = true;
				}

				if (preMatched)
				{
					str = str.left(i) + after + delimiter + str.right(str.length() - i - before.length());
					i += after.length() + delimiter.length();
				}
				else
				{
					str = str.left(i) + delimiter + after + delimiter + str.right(str.length() - i - before.length());
					i += after.length() + 2 * delimiter.length();
				}
				bool changed = uppercaseCharFollowingCtrl(str, i, after);
				preMatched = !changed;
			}
			if (preMatched)
			{
				int len;
				if (existingDelimiters != NULL &&
				    (len = isDelimiterExistedAfter(str.right(str.length() - i), *existingDelimiters)) != 0)
				{
					str = str.left(i) + str.right(str.length() - i - len);
				}
			}
        }else{
			preMatched = false;
			++i;
		}
	}// end of while
}

void FQTermFrame::transEscapeStr(QString& target, const QString& source) {
	const QChar cSpecial(17);
	target = source;
	replaceEscapeString(target, QString("^["), QString("ESC"), QString(cSpecial));
	std::vector<QString> existingDelimiters;
	existingDelimiters.push_back(QString(cSpecial));
	replaceEscapeString(target, QString("^"), QString("Ctrl"), QString("+"), &existingDelimiters);
	target.replace(cSpecial, QChar(' '));
}

void FQTermFrame::setColor() {
	windowManager_->activeWindow()->setColor();
}

void FQTermFrame::refreshScreen() {
	windowManager_->activeWindow()->forcedRepaintScreen();
}

void FQTermFrame::uiFont() {
	bool ok;
	QFont font = QFontDialog::getFont(&ok, qApp->font());

	if (FQTermPref::getInstance()->openAntiAlias_) {
		font.setStyleStrategy(QFont::PreferAntialias);
	}

	if (ok == true) {
		qApp->setFont(font);
		//refresh style sheet
		if (FQTermPref::getInstance()->useStyleSheet_) {
			refreshStyleSheet();
		}
		imageViewer_->adjustItemSize();
	}
}

void FQTermFrame::fullscreen()
{
	if (!(windowState() & Qt::WindowFullScreen)) {
		menuBar()->hide();
		toolBarMdiTools_->hide();
		toolBarMdiConnectTools_->hide();
		toolBarSetupKeys_->hide();
		toolBarFonts_->hide();
		hideScroll();
		showSwitchBar();
		showFullScreen();
	} else {
		menuBar()->show();
		toolBarMdiTools_->show();
		toolBarMdiConnectTools_->show();
		toolBarSetupKeys_->show();
		toolBarFonts_->show();
		emit updateScroll();
		showSwitchBar();
		showNormal();
	}

}

void FQTermFrame::bosscolor() {
	FQTermPref::getInstance()->isBossColor_ = !FQTermPref::getInstance()->isBossColor_;
	emit bossColor();
	getAction(FQTermShortcutHelper::BOSSCOLOR)->setChecked(FQTermPref::getInstance()->isBossColor_);
}


void FQTermFrame::themesMenuAboutToShow() {
	QVector<QChar> vectorShortcutKeys;
	menuThemes_->clear();
	QStringList styles = QStyleFactory::keys();
	for (QStringList::ConstIterator it = styles.begin();
	     it != styles.end(); it++) {
		QString strTheme = *it;
		for (int i = 0; i < strTheme.length(); ++i)
		{
			if (vectorShortcutKeys.indexOf(strTheme.at(i)) == -1)
			{
				vectorShortcutKeys.append(strTheme.at(i));
				strTheme.insert(i, QChar('&'));
				break;
			}
		}
		insertThemeItem(strTheme);
	}
#ifdef USE_DOTNET_STYLE
	insertThemeItem("Office");  //javaboy@newsmth.org
#endif //USE_DOTNET_STYLE
}

void FQTermFrame::themesMenuActivated() {
	theme_ = ((QAction*)QObject::sender())->text().remove(QChar('&'));
	QStyle *style;
#ifdef USE_DOTNET_STYLE
	//javaboy@newsmth.org
	if (theme_ == "Office")
		style = new DotNetStyle(DotNetStyle::Office);
	else
#endif //USE_DOTNET_STYLE
		style = QStyleFactory::create(theme_);
	if (style) {
		qApp->setStyle(style);
	}
}



void FQTermFrame::hideScroll() {
	FQTermPref::getInstance()->termScrollBarPosition_ = 0;
	emit updateScroll();
}

void FQTermFrame::leftScroll() {
	FQTermPref::getInstance()->termScrollBarPosition_ = 1;
	emit updateScroll();
}

void FQTermFrame::rightScroll() {
	FQTermPref::getInstance()->termScrollBarPosition_ = 2;
	emit updateScroll();
}

void FQTermFrame::setSE(const QString& se) {
	FQTermPref::getInstance()->searchEngine_ = se;
	config_->setItemValue("preference", "searchengine", se);
}

void FQTermFrame::setSEBaidu(){
	setSE("baidu");
}
void FQTermFrame::setSECustom(){
	setSE("custom");
}

void FQTermFrame::showSwitchBar() {
	isTabBarShown_ = !isTabBarShown_;
	getAction(FQTermShortcutHelper::SWITCHBAR)->setChecked(isTabBarShown_);

	if (isTabBarShown_) {
		statusBar()->show();
	} else {
		statusBar()->hide();
	}
}

void FQTermFrame::setting() {
	windowManager_->activeWindow()->setting();
	updateMenuToolBar();
}

void FQTermFrame::saveSessionSetting() {
	windowManager_->activeWindow()->saveSetting(false);
}

void FQTermFrame::defaultSetting() {
	FQTermConfig *pConf = new FQTermConfig(getPath(USER_CONFIG) + "address.cfg");
	FQTermParam tmpParam;
 
	if (pConf->hasSection("default")) {
		loadAddress(pConf, -1, tmpParam);
	}

	addrDialog set(this, tmpParam, addrDialog::SAVE);

	if (set.exec() == 2) {
		saveAddress(pConf, -1, set.param());
		pConf->save(getPath(USER_CONFIG) + "address.cfg");
	}

	delete pConf;
}

void FQTermFrame::preference() {
	prefDialog pref(config_, this);
	bool styleSheetUsed = FQTermPref::getInstance()->useStyleSheet_;

	if (pref.exec() == 1) {
		//TODO: refactor
		loadPref();
		setUseDock(FQTermPref::getInstance()->openMinimizeToTray_);
		if (FQTermPref::getInstance()->useStyleSheet_) {
			loadStyleSheetFromFile(FQTermPref::getInstance()->styleSheetFile_);
		}
		else if (styleSheetUsed) {
			clearStyleSheet();
		}
	}
	emit fontAntiAliasing(FQTermPref::getInstance()->openAntiAlias_);
}

void FQTermFrame::shortcutSetting() {
	int act = windowManager_->activeWindowIndex();
	FQTermShortcutDialog fsd(shortcutHelper_, this);
	fsd.exec();
	windowManager_->activateTheWindow(act);
}

void FQTermFrame::keySetup() {
	keyDialog keyDlg(config_, this);
	if (keyDlg.exec() == 1) {
		updateKeyToolBar();
	}
}


void FQTermFrame::ipLookup() {
	IPLookupDialog ipLookupDialog_(this);
	ipLookupDialog_.exec();
}

void FQTermFrame::logRaw() 
{
	FQTermSession *s = windowManager_->activeWindow()->getSession();

	if (!s->isLogging()) {
		s->startLogging();
	}
	else {
		s->stopLogging(true);
	}

	getAction(FQTermShortcutHelper::LOGRAW)->setChecked(
		s->isLogging());
}
    
void FQTermFrame::antiIdle() {
	windowManager_->activeWindow()->toggleAntiIdle();
	getAction(FQTermShortcutHelper::ANTIIDLE)->setChecked(
		windowManager_->activeWindow()->getSession()->isAntiIdle());
}

void FQTermFrame::autoReply() {
	windowManager_->activeWindow()->toggleAutoReply();
	getAction(FQTermShortcutHelper::AUTOREPLY)->setChecked(
		windowManager_->activeWindow()->getSession()->isAutoReply());
}

void FQTermFrame::viewMessages() {
	windowManager_->activeWindow()->viewMessages();
}

void FQTermFrame::enableMouse() {
	windowManager_->activeWindow()->getSession()->param().isSupportMouse_
		= !windowManager_->activeWindow()->getSession()->param().isSupportMouse_;
	getAction(FQTermShortcutHelper::MOUSESUPPORT)->setChecked(
		windowManager_->activeWindow()->getSession()->param().isSupportMouse_);
}

void FQTermFrame::viewImages(QString filename, bool raiseViewer) {
	if (filename.isEmpty()) {
		filename = FQTermPref::getInstance()->poolDir_;
	}

	if (raiseViewer) {
		imageViewer_->scrollTo(filename);
		if (imageViewer_->isHidden()) {
			imageViewer_->resize(size() * 3 / 4 + QSize(1,1));
			imageViewer_->show();
		}
		clearFocus();
		imageViewer_->raise();
		imageViewer_->activateWindow();
	} else {
		imageViewer_->updateImage(filename);
	}
}

void FQTermFrame::viewImages() {
	viewImages(FQTermPref::getInstance()->poolDir_, true);
}

void FQTermFrame::beep() {
	windowManager_->activeWindow()->getSession()->param().isBeep_ =
		!windowManager_->activeWindow()->getSession()->param().isBeep_;
	getAction(FQTermShortcutHelper::BEEP)->setChecked(windowManager_->activeWindow()->getSession()->param().isBeep_);
}

void FQTermFrame::reconnect() {
	FQTermWindow * qtw = windowManager_->activeWindow();
	if (qtw){
		qtw->toggleAutoReconnect();
	}
}


void FQTermFrame::delayedRunScript() {
	windowManager_->activeWindow()->runScript();
}


void FQTermFrame::runScript() {
	QTimer::singleShot(1, this, SLOT(delayedRunScript()));
}

void FQTermFrame::stopScript() {
	windowManager_->activeWindow()->stopScript();
}


void FQTermFrame::runPyScript() {
#ifdef HAVE_PYTHON
	windowManager_->activeWindow()->runPythonScript();
#endif //HAVE_PYTHON
}

bool FQTermFrame::event(QEvent *e) {

	static bool shown = false;
	if (e->type() == QEvent::WindowStateChange) {
		if ((((QWindowStateChangeEvent*)(e))->oldState() & Qt::WindowMinimized)
		    && !(windowState() & Qt::WindowMinimized)) {
			shown = true;
		}
		if (!(windowState() & Qt::WindowMinimized))
		{
			config_->setItemValue("global", "max", (windowState() & Qt::WindowMaximized) ? "1" : "0");
			config_->setItemValue("global", "fullscreen", (windowState() & Qt::WindowFullScreen) ? "1" : "0");
		}
	}
	if (e->type() == QEvent::Paint && shown) {
		shown = false;
		qApp->setActiveWindow(NULL);
		qApp->setActiveWindow(this);
	}

	bool res = this->QMainWindow::event(e);

	if (e->type() == QEvent::HoverMove
	    || e->type() == QEvent::MouseMove
	    || e->type() == QEvent::Move) {
		if (res) {
			FQ_TRACE("frameEvent", 10) << "Accept event: " << e->type()
						   << " " << getEventName(e->type()) << ".";
		} else {
			FQ_TRACE("frameEvent", 10) << "Ignore event: " << e->type()
						   << " " << getEventName(e->type()) << ".";
		}
	} else {
		if (res) {
			FQ_TRACE("frameEvent", 9) << "Accept event: " << e->type()
						  << " " << getEventName(e->type()) << ".";
		} else {
			FQ_TRACE("frameEvent", 9) << "Ignore event: " << e->type()
						  << " " << getEventName(e->type()) << ".";
		}
	}

	return res;
}

void FQTermFrame::keyClicked(int id) {
	if (windowManager_->activeWindow() == NULL) {
		return ;
	}

	QString strItem = QString("key%1").arg(id);
	QString strTmp = config_->getItemValue("key", strItem);

	if (strTmp[0] == '0') { // key
		windowManager_->activeWindow()->externInput(strTmp.mid(1));
	} else if (strTmp[0] == '1') { // script
		QString scriptFile = strTmp.mid(1).trimmed();
#ifdef HAVE_PYTHON
		if (scriptFile.endsWith(".py", Qt::CaseInsensitive))
			windowManager_->activeWindow()->runPythonScriptFile(scriptFile);
		else
#endif
			windowManager_->activeWindow()->runScript(scriptFile.toLatin1());
	} else if (strTmp[0] == '2') { // program
		runProgram(strTmp.mid(1));
	}
}

void FQTermFrame::addMainTool()
{
	// the main toolbar
	toolBarMdiTools_ = addToolBar("Main ToolBar");
	toolBarMdiTools_->setObjectName("Main ToolBar");

	connectButton_ = new QToolButton(toolBarMdiTools_);
	connectButton_->setIcon(QPixmap(getPath(RESOURCE) + "pic/connect.png"));

	toolBarMdiTools_->addWidget(connectButton_);
	menuConnect_ = new QMenu(this);
	//FIXME: autoupdate menu
	FQ_VERIFY(connect(menuConnect_, SIGNAL(aboutToShow()),
			  this, SLOT(popupConnectMenu())));
	connectButton_->setMenu(menuConnect_);
	connectButton_->setPopupMode(QToolButton::InstantPopup);

	toolBarMdiTools_->addAction(getAction(FQTermShortcutHelper::QUICKLOGIN));

	// custom define
    /*toolBarSetupKeys_ = addToolBar("Custom Key");
    toolBarSetupKeys_->setObjectName("Custom Key");*/

	// the toolbar
    toolBarMdiConnectTools_ = addToolBar("BBS operations");
	toolBarMdiConnectTools_->setObjectName("BBS operations");
	toolBarMdiConnectTools_->addAction(getAction(FQTermShortcutHelper::CONN_INFO));
	FQTERM_ADDACTION(toolBarMdiConnectTools_, DISCONNECT, this, disconnect);
	getAction(FQTermShortcutHelper::DISCONNECT)->setEnabled(false);
    toolBarMdiConnectTools_->addSeparator();

	//Font Tool Bar
    /*toolBarFonts_ = addToolBar("Font ToolBar");
    toolBarFonts_->setObjectName("Font ToolBar");*/

	// Edit (5)
    toolBarMdiConnectTools_->addAction(getAction(FQTermShortcutHelper::COPY));
	toolBarMdiConnectTools_->addAction(getAction(FQTermShortcutHelper::PASTE));
	toolBarMdiConnectTools_->addAction(getAction(FQTermShortcutHelper::COPYWITHCOLOR));
	toolBarMdiConnectTools_->addAction(getAction(FQTermShortcutHelper::RECTANGLESELECTION));
    toolBarMdiConnectTools_->addSeparator();

	//Font
/*	fontButton_ = new QToolButton(toolBarFonts_);
	QAction* dummyAction = new QAction(QPixmap(getPath(RESOURCE) + "pic/change_fonts.png"),
					   tr("Set Terminal Fonts"), fontButton_);
	fontButton_->setDefaultAction(dummyAction);
	toolBarFonts_->addWidget(fontButton_);
	fontButton_->setMenu(menuFont_);
	fontButton_->setPopupMode(QToolButton::InstantPopup);

	toolBarFonts_->addSeparator();
	englishFontCombo_ = new QFontComboBox(toolBarFonts_);
	otherFontCombo_ = new QFontComboBox(toolBarFonts_);
	QLabel *englishFontLabel = new QLabel(toolBarFonts_);
	englishFontLabel->setPixmap(QPixmap(getPath(RESOURCE) + "pic/english_font.png"));
	toolBarFonts_->addWidget(englishFontLabel);
	toolBarFonts_->addWidget(englishFontCombo_);
	toolBarFonts_->addSeparator();
	QLabel *otherFontLabel = new QLabel(toolBarFonts_);
	otherFontLabel->setPixmap(QPixmap(getPath(RESOURCE) + "pic/other_font.png"));
	toolBarFonts_->addWidget(otherFontLabel);
	toolBarFonts_->addWidget(otherFontCombo_);
	FQ_VERIFY(connect(englishFontCombo_, SIGNAL(currentFontChanged(const QFont&)),
			  this, SLOT(comboFontChanged(const QFont&))));
	FQ_VERIFY(connect(otherFontCombo_, SIGNAL(currentFontChanged(const QFont&)),
			  this, SLOT(comboFontChanged(const QFont&))));

	toolBarMdiConnectTools_->addAction(getAction(FQTermShortcutHelper::COLORSETTING));
	toolBarMdiConnectTools_->addAction(getAction(FQTermShortcutHelper::ANSICOLOR));
	toolBarMdiConnectTools_->addAction(getAction(FQTermShortcutHelper::REFRESHSCREEN));
	toolBarMdiConnectTools_->addSeparator();
*/
	// Option
    toolBarMdiConnectTools_->addAction(getAction(FQTermShortcutHelper::CURRENTSETTING));
	toolBarMdiConnectTools_->addAction(getAction(FQTermShortcutHelper::SAVESETTING));
    toolBarMdiConnectTools_->addSeparator();

	// Spec (5)
    //toolBarMdiConnectTools_->addAction(getAction(FQTermShortcutHelper::COPYARTICLE));
    //toolBarMdiConnectTools_->addAction(getAction(FQTermShortcutHelper::LOGRAW));
    //toolBarMdiConnectTools_->addAction(getAction(FQTermShortcutHelper::ANTIIDLE));
    //toolBarMdiConnectTools_->addAction(getAction(FQTermShortcutHelper::AUTOREPLY));
    //toolBarMdiConnectTools_->addAction(getAction(FQTermShortcutHelper::VIEWMESSAGE));
    //toolBarMdiConnectTools_->addAction(getAction(FQTermShortcutHelper::IMAGEVIEWER));
	toolBarMdiConnectTools_->addAction(getAction(FQTermShortcutHelper::MOUSESUPPORT));
	toolBarMdiConnectTools_->addAction(getAction(FQTermShortcutHelper::BEEP));
	toolBarMdiConnectTools_->addAction(getAction(FQTermShortcutHelper::AUTORECONNECT));

	//call popupConnectMenu() to enable the shortcuts
	popupConnectMenu(); 
}


QAction* FQTermFrame::getAction(int shortcut) {
	if (!shortcutHelper_)
		return NULL;
	return shortcutHelper_->getAction(shortcut);
}



void FQTermFrame::addMainMenu()
{
	menuMain_ = menuBar(); 

	//File Menu
	menuFile_ = menuMain_->addMenu(tr("&File"));

    //FQTERM_ADDACTION(menuFile_, CONNECT, this, connectIt);
    FQTERM_ADDACTION(menuFile_, DISCONNECT, this, disconnect);
	FQTERM_ADDACTION(menuFile_, CONN_INFO, this, conn_info);
	menuFile_->addSeparator();
	FQTERM_ADDACTION(menuFile_, ADDRESSBOOK, this, addressBook);
	FQTERM_ADDACTION(menuFile_, QUICKLOGIN, this, quickLogin);
	menuFile_->addSeparator();
	FQTERM_ADDACTION(menuFile_, EXIT, this, exitFQTerm);
	getAction(FQTermShortcutHelper::EXIT)->setMenuRole(QAction::QuitRole);

	//Edit Menu
	QMenu *edit = menuMain_->addMenu(tr("&Edit"));

	FQTERM_ADDACTION(edit, COPY, this, copy);
	FQTERM_ADDACTION(edit, PASTE, this, paste);
	edit->addSeparator();
	FQTERM_ADDACTION(edit, COPYWITHCOLOR, this, copyColor);
	FQTERM_ADDACTION(edit, RECTANGLESELECTION, this, copyRect);
	FQTERM_ADDACTION(edit, AUTOCOPYSELECTION, this, autoCopy);
	FQTERM_ADDACTION(edit, PASTEWORDWRAP, this, wordWrap);
	edit->addSeparator();
	FQTERM_ADDACTION(edit, SEARCHIT, this, searchIt);
    FQTERM_ADDACTION(edit, WEIBOSHARE, this, shareIt);
	edit->addSeparator();
	FQTERM_ADDACTION(edit, EXTERNALEDITOR, this, externalEditor);
    edit->addSeparator();
    FQTERM_ADDACTION(edit, FASTPOST, this, fastPost);
	edit->addSeparator();

	QMenu *escapeMenu = edit->addMenu(tr("Control sequence in clipboar&d"));
	escapeGroup = new QActionGroup(this);
	FQTERM_ADDACTION(escapeMenu, COLORCTL_NO,this, noEsc);
	escapeGroup->addAction(getAction(FQTermShortcutHelper::COLORCTL_NO));
	FQTERM_ADDACTION(escapeMenu, COLORCTL_SMTH,this, escEsc);
	escapeGroup->addAction(getAction(FQTermShortcutHelper::COLORCTL_SMTH));
	FQTERM_ADDACTION(escapeMenu, COLORCTL_PTT,this, uEsc);
	escapeGroup->addAction(getAction(FQTermShortcutHelper::COLORCTL_PTT));
	FQTERM_ADDACTION(escapeMenu, COLORCTL_OLD_CUSTOM,this, oldCustomEsc);
	escapeGroup->addAction(getAction(FQTermShortcutHelper::COLORCTL_OLD_CUSTOM));
	FQTERM_ADDACTION(escapeMenu, COLORCTL_CUSTOM,this, customEsc);
	escapeGroup->addAction(getAction(FQTermShortcutHelper::COLORCTL_CUSTOM));

	//View menu
	QMenu *view = menuMain_->addMenu(tr("&View"));

	menuFont_ = view->addMenu(tr("&Font"));
	menuFont_->setIcon(QPixmap(getPath(RESOURCE) + "pic/change_fonts.png"));
	view->addMenu(menuFont_);
	FQTERM_ADDACTION(menuFont_, OTHERFONT, this, setFont);
	getAction(FQTermShortcutHelper::OTHERFONT)->setData(0);
	FQTERM_ADDACTION(menuFont_, ENGLISHFONT, this, setFont);
	getAction(FQTermShortcutHelper::ENGLISHFONT)->setData(1);
	FQTERM_ADDACTION(view, COLORSETTING, this, setColor);
	FQTERM_ADDACTION(view, ANSICOLOR, this, toggleAnsiColor);
	FQTERM_ADDACTION(view, REFRESHSCREEN, this, refreshScreen);
	view->addSeparator();

	//language menu
	languageGroup = new QActionGroup(view);
	languageGroup->setExclusive(true);
	if (installerList_.isEmpty()) {
		FQ_TRACE("frame", 0)
			<< "No language menu because of lack of translation files";
	} else {
		menuLanguage_ = view->addMenu(tr("&Language"));
		FQTERM_ADDACTION(menuLanguage_, LANGUAGE_ENGLISH, this, langEnglish);
		languageGroup->addAction(getAction(FQTermShortcutHelper::LANGUAGE_ENGLISH));

		foreach(TranslatorInstaller* installer, installerList_) {
			QAction* action = menuLanguage_->addAction(
				installer->languageName(), installer, SLOT(installTranslator()));
			action->setCheckable(true);
			languageGroup->addAction(action);
		}

	} 

	FQTERM_ADDACTION(view, UIFONT, this, uiFont);

	menuThemes_ = view->addMenu(tr("&Themes"));
	FQ_VERIFY(connect(menuThemes_, SIGNAL(aboutToShow()), this, SLOT(themesMenuAboutToShow())));

	FQTERM_ADDACTION(view, FULLSCREEN, this, fullscreen);
	FQTERM_ADDACTION(view, BOSSCOLOR, this, bosscolor);

	view->addSeparator();

	QMenu *scrollMenu = view->addMenu(tr("&ScrollBar"));  
	scrollGroup = new QActionGroup(this);
	FQTERM_ADDACTION(scrollMenu, SCROLLBAR_HIDDEN,this, hideScroll);
	scrollGroup->addAction(getAction(FQTermShortcutHelper::SCROLLBAR_HIDDEN));
	FQTERM_ADDACTION(scrollMenu, SCROLLBAR_RIGHT,this, rightScroll);
	scrollGroup->addAction(getAction(FQTermShortcutHelper::SCROLLBAR_RIGHT));
	FQTERM_ADDACTION(scrollMenu, SCROLLBAR_LEFT,this, leftScroll);
	scrollGroup->addAction(getAction(FQTermShortcutHelper::SCROLLBAR_LEFT));

	FQTERM_ADDACTION(view, SWITCHBAR, this, showSwitchBar);
	// Option Menu
	QMenu *option = menuMain_->addMenu(tr("&Option"));

	FQTERM_ADDACTION(option, CURRENTSETTING, this, setting);
	FQTERM_ADDACTION(option, SAVESETTING, this, saveSessionSetting);
	option->addSeparator();
	FQTERM_ADDACTION(option, DEFAULTSETTING, this, defaultSetting);

	FQTERM_ADDACTION(option, PREFERENCE, this, preference);

	getAction(FQTermShortcutHelper::PREFERENCE)->setMenuRole(QAction::PreferencesRole);
	FQTERM_ADDACTION(option, SHORTCUTSETTING, this, shortcutSetting);
	option->addSeparator();
	FQTERM_ADDACTION(option, EDITSCHEMA, this, editSchema);
	option->addSeparator();

	QMenu *searchEngineMenu = option->addMenu(tr("Searc&h Engine"));
	searchEngineGroup = new QActionGroup(this);

	FQTERM_ADDACTION(searchEngineMenu, SEARCH_BAIDU,this, setSEBaidu);
	searchEngineGroup->addAction(getAction(FQTermShortcutHelper::SEARCH_BAIDU));
	FQTERM_ADDACTION(searchEngineMenu, SEARCH_CUSTOM,this, setSECustom);
	searchEngineGroup->addAction(getAction(FQTermShortcutHelper::SEARCH_CUSTOM));

	// Special
    //QMenu *spec = menuMain_->addMenu(tr("&Special"));
    //FQTERM_ADDACTION(spec, COPYARTICLE, this, copyArticle);
    //FQTERM_ADDACTION(spec, LOGRAW, this, logRaw);
    //FQTERM_ADDACTION(spec, ANTIIDLE, this, antiIdle);
    //FQTERM_ADDACTION(spec, AUTOREPLY, this, autoReply);
    //FQTERM_ADDACTION(spec, VIEWMESSAGE, this, viewMessages);
    //FQTERM_ADDACTION(spec, BEEP, this, beep);
    //FQTERM_ADDACTION(spec, MOUSESUPPORT, this, enableMouse);
    //FQTERM_ADDACTION(spec, IMAGEVIEWER, this, viewImages);
    //FQTERM_ADDACTION(spec, IPLOOKUP, this, ipLookup);

	//Script
    // FIXME 2022-12-30 临时放弃脚本相关功能，在后续条件成熟后添加
    /*QMenu *script = menuMain_->addMenu(tr("Scrip&t"));
	FQTERM_ADDACTION(script, RUNSCRIPT, this, runScript);
	FQTERM_ADDACTION(script, STOPSCRIPT, this, stopScript);
#ifdef HAVE_PYTHON
	script->addSeparator();
	FQTERM_ADDACTION(script, RUNPYTHONSCRIPT, this, runPyScript);
#endif //HAVE_PYTHON
    */
	//Window menu
	menuWindows_ = menuMain_->addMenu(tr("&Windows"));
	FQ_VERIFY(connect(menuWindows_, SIGNAL(aboutToShow()),this, SLOT(windowsMenuAboutToShow())));
	menuMain_->addSeparator();

	//Help menu
	QMenu *help = menuMain_->addMenu(tr("&Help"));
	FQTERM_ADDACTION(help, ABOUT, this, aboutFQTerm);
	getAction(FQTermShortcutHelper::ABOUT)->setMenuRole(QAction::AboutRole);
	FQTERM_ADDACTION(help, HOMEPAGE, this, homepage);
}

void FQTermFrame::updateMenuToolBar() {
	FQTermWindow *window = windowManager_->activeWindow();

	if (window == NULL) {
		return ;
	}

	// update menu
	getAction(FQTermShortcutHelper::CONN_INFO)->setEnabled(window->isConnected());
	getAction(FQTermShortcutHelper::DISCONNECT)->setEnabled(window->isConnected());
	getAction(FQTermShortcutHelper::COPYWITHCOLOR)->setChecked(window->getSession()->param().isColorCopy_);
	getAction(FQTermShortcutHelper::RECTANGLESELECTION)->setChecked(window->getSession()->param().isRectSelect_);
	getAction(FQTermShortcutHelper::AUTOCOPYSELECTION)->setChecked(window->getSession()->param().isAutoCopy_);
	getAction(FQTermShortcutHelper::PASTEWORDWRAP)->setChecked(window->getSession()->param().isAutoWrap_);
	getAction(FQTermShortcutHelper::FULLSCREEN)->setChecked(windowState() & Qt::WindowFullScreen);
	getAction(FQTermShortcutHelper::ANSICOLOR)->setChecked(window->getSession()->param().isAnsiColor_);
	getAction(FQTermShortcutHelper::LOGRAW)->setChecked(window->getSession()->isLogging());
	getAction(FQTermShortcutHelper::ANTIIDLE)->setChecked(window->getSession()->isAntiIdle());
	getAction(FQTermShortcutHelper::AUTOREPLY)->setChecked(window->getSession()->isAutoReply());
	getAction(FQTermShortcutHelper::BEEP)->setChecked(window->getSession()->param().isBeep_);
	getAction(FQTermShortcutHelper::MOUSESUPPORT)->setChecked(window->getSession()->param().isSupportMouse_);
	getAction(FQTermShortcutHelper::AUTORECONNECT)->setChecked(window->getSession()->param().isAutoReconnect_);

	updateFontCombo();
}

void FQTermFrame::updateFontCombo() {
	FQTermWindow *window = windowManager_->activeWindow();

	if (window == NULL) {
		return ;
	}
    //englishFontCombo_->blockSignals(true);
    //otherFontCombo_->blockSignals(true);
    //englishFontCombo_->setCurrentFont(window->getScreen()->termFont(true));
    //otherFontCombo_->setCurrentFont(window->getScreen()->termFont(false));
    //englishFontCombo_->blockSignals(false);
    //otherFontCombo_->blockSignals(false);
}

void FQTermFrame::termFontChange(bool isEnglish, QFont font) {
	updateFontCombo();
}

void FQTermFrame::comboFontChanged(const QFont & font) {

	FQTermWindow *window = windowManager_->activeWindow();

	if (window == NULL) {
		return ;
	}
  
	window->getScreen()->blockSignals(true);

	bool isEnglish = (sender() == (QObject*)englishFontCombo_);

	QString& fontName = isEnglish?
		window->getSession()->param().englishFontName_:window->getSession()->param().otherFontName_;
	int& fontSize = isEnglish?
		window->getSession()->param().englishFontSize_:window->getSession()->param().otherFontSize_;
	QFontComboBox* combo = isEnglish ? englishFontCombo_ : otherFontCombo_;

	QFont f(combo->currentFont().family(), window->getScreen()->termFont(true).pointSize());

	window->getScreen()->setTermFont(isEnglish, f);

	fontName = f.family();
	fontSize = f.pointSize();

	window->getScreen()->blockSignals(false);

	window->forcedRepaintScreen();
}

void FQTermFrame::enableMenuToolBar(bool enable) {
	getAction(FQTermShortcutHelper::CONN_INFO)->setEnabled(enable);
	getAction(FQTermShortcutHelper::DISCONNECT)->setEnabled(enable);
	getAction(FQTermShortcutHelper::COPY)->setEnabled(enable);
	getAction(FQTermShortcutHelper::PASTE)->setEnabled(enable);
	getAction(FQTermShortcutHelper::COPYWITHCOLOR)->setEnabled(enable);
	getAction(FQTermShortcutHelper::RECTANGLESELECTION)->setEnabled(enable);
	getAction(FQTermShortcutHelper::AUTOCOPYSELECTION)->setEnabled(enable);
	getAction(FQTermShortcutHelper::PASTEWORDWRAP)->setEnabled(enable);
	getAction(FQTermShortcutHelper::ANSICOLOR)->setEnabled(enable);

    //fontButton_->setEnabled(enable);
//	englishFontCombo_->setEnabled(enable);
    //otherFontCombo_->setEnabled(enable);
    //menuFont_->setEnabled(enable);

	getAction(FQTermShortcutHelper::COLORSETTING)->setEnabled(enable);
	getAction(FQTermShortcutHelper::REFRESHSCREEN)->setEnabled(enable);
	getAction(FQTermShortcutHelper::CURRENTSETTING)->setEnabled(enable);
	getAction(FQTermShortcutHelper::SAVESETTING)->setEnabled(enable);
	getAction(FQTermShortcutHelper::COPYARTICLE)->setEnabled(enable);
	getAction(FQTermShortcutHelper::LOGRAW)->setEnabled(enable);
	getAction(FQTermShortcutHelper::ANTIIDLE)->setEnabled(enable);
	getAction(FQTermShortcutHelper::AUTOREPLY)->setEnabled(enable);
	getAction(FQTermShortcutHelper::VIEWMESSAGE)->setEnabled(enable);
	getAction(FQTermShortcutHelper::BEEP)->setEnabled(enable);
	getAction(FQTermShortcutHelper::MOUSESUPPORT)->setEnabled(enable);
	getAction(FQTermShortcutHelper::RUNSCRIPT)->setEnabled(enable);
	getAction(FQTermShortcutHelper::STOPSCRIPT)->setEnabled(enable);
#ifdef HAVE_PYTHON
	getAction(FQTermShortcutHelper::RUNPYTHONSCRIPT)->setEnabled(enable);
#endif 
	getAction(FQTermShortcutHelper::SEARCHIT)->setEnabled(enable);
	getAction(FQTermShortcutHelper::WEIBOSHARE)->setEnabled(enable);
	getAction(FQTermShortcutHelper::EXTERNALEDITOR)->setEnabled(enable);
	getAction(FQTermShortcutHelper::FASTPOST)->setEnabled(enable);
}

void FQTermFrame::updateKeyToolBar()
{
    //toolBarSetupKeys_->clear();
    //toolBarSetupKeys_->addAction(QPixmap(getPath(RESOURCE) + "pic/setup_shortcuts.png"),
    //			     tr("Key Setup"), this, SLOT(keySetup()));

	QString strItem, strTmp;
	strTmp = config_->getItemValue("key", "num");
	int num = strTmp.toInt();

	for (int i = 0; i < num; i++) {
		strItem = QString("name%1").arg(i);
		strTmp = config_->getItemValue("key", strItem);
		FQTermToolButton *button =
			new FQTermToolButton(toolBarSetupKeys_, i, strTmp);
		button->setText(strTmp);
		strItem = QString("key%1").arg(i);
		strTmp = (config_->getItemValue("key", strItem));
		//TODO: add tool tip here
		// 		QToolTip::add( button, strTmp.mid(1) );
		// 		button->addToolTip(strTmp.mid(1));

		strTmp = config_->getItemValue("key", QString("shortcut%1").arg(i));
		if (!strTmp.isEmpty()) {
			QAction *act = new QAction(button);
			act->setShortcut(strTmp);
			button->addAction(act);
			FQ_VERIFY(connect(act, SIGNAL(triggered()), button, SLOT(slotClicked())));
		}

		FQ_VERIFY(connect(button, SIGNAL(buttonClicked(int)),
				  this, SLOT(keyClicked(int))));
		toolBarSetupKeys_->addWidget(button);
	}



}


void FQTermFrame::popupFocusIn(FQTermWindow*) {
	// bring to font
	if (isHidden()) {
		show();
	}
	if (isMinimized()) {
		if (isMaximized()) {
			showMaximized();
		} else {
			showNormal();
		}
	}
	raise();
	activateWindow();
}

void FQTermFrame::insertThemeItem(const QString& themeitem) {
	QAction *idAction;

	idAction = menuThemes_->addAction(themeitem,
					  this, SLOT(themesMenuActivated()));
	idAction->setCheckable(true);
	idAction->setChecked(themeitem == theme_);
}

void FQTermFrame::setUseDock(bool use) {
	if (use == false) {
		if (tray_) {
			tray_->hide();
			delete tray_;
			tray_ = 0;
			//delete menuTray_;
			//menuTray_ = 0;
		}
		return ;
	}

	if (tray_ || !QSystemTrayIcon::isSystemTrayAvailable()) {
		return ;
	}

	trayMenu_ = new QMenu;
	FQ_VERIFY(connect(trayMenu_, SIGNAL(aboutToShow()), SLOT(buildTrayMenu())));

	tray_ = new QSystemTrayIcon(this);
	tray_->setIcon(QPixmap(getPath(RESOURCE) + "pic/fqterm_tray.png"));
	tray_->setContextMenu(trayMenu_);
	FQ_VERIFY(connect(tray_, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
			  SLOT(trayActived(QSystemTrayIcon::ActivationReason))));
	tray_->show();
}

void FQTermFrame::buildTrayMenu() {
	if (!trayMenu_) {
		return ;
	}
	trayMenu_->clear();

	if (isHidden()) {
		trayMenu_->addAction(tr("Show"), this, SLOT(trayShow()));
	} else {
		trayMenu_->addAction(tr("Hide"), this, SLOT(trayHide()));
	}
	trayMenu_->addSeparator();
	trayMenu_->addAction(tr("About"), this, SLOT(aboutFQTerm()));
	trayMenu_->addAction(tr("Exit"), this, SLOT(exitFQTerm()));
}

void FQTermFrame::trayActived(QSystemTrayIcon::ActivationReason reason) {
	if (reason == QSystemTrayIcon::Context) {
		return ;
	}
	if (!isVisible()) {
		trayShow();
	} else {
		trayHide();
	}
}

void FQTermFrame::trayShow() {
	show();
	// bring to font
	if (isHidden()) {
		show();
	}
	if (isMinimized()) {
		if (isMaximized()) {
			showMaximized();
		} else {
#ifdef Q_OS_MACX
			showMaximized();
#else
			showNormal();
#endif
		}
	}
	raise();
	activateWindow();
	FQTermWindow* window = windowManager_->activeWindow();
	if (window) {
		window->forcedRepaintScreen();
		if (!window->isMaximized()) {
			windowManager_->refreshAllExcept(window);
		}
	}
}

void FQTermFrame::trayHide() {
	static bool showTip = true;
	QString str = config_->getItemValue("global", "traytipshown");
	if (str == "1") {
		showTip = false;
	}
	hide();
	if (showTip && tray_) {
	tray_->showMessage(tr("vTerminal"),
		   tr("vTerminal will keep running in the system tray.\n"
				      "To terminate the program, "
				      "choose exit in the tray menu."));
		showTip = false;
		config_->setItemValue("global", "traytipshown", "1");
	}
}

void FQTermFrame::buzz(FQTermWindow* window)
{
	if (windowManager_->activeWindow() == window)
		return;
	int xp = x();
	int yp = y();
	QTime t;

	t.start();
	for (int i = 32; i > 0;) {
		if (t.elapsed() >= 1) {
			int delta = i >> 2;
			int dir = i &3;
			int dx = ((dir == 1) || (dir == 2)) ? delta : -delta;
			int dy = (dir < 2) ? delta : -delta;
			move(xp + dx, yp + dy);
			t.restart();
			i--;
		}
	}
	move(xp, yp);
}


//--------------------------
//recreate the main menu
//--------------------------
void
FQTermFrame::recreateMenu() {

	if (shortcutHelper_) {
		shortcutHelper_->retranslateActions();
	}
	menuBar()->clear();
	delete escapeGroup;
	delete languageGroup;
	addMainMenu();
	updateLanguageMenu();

	QString strTmp = QString(saveState().toHex());
	config_->setItemValue("global", "toolbarstate", strTmp);
	config_->save(getPath(USER_CONFIG) + "fqterm.cfg");

	delete toolBarMdiTools_;
	delete toolBarSetupKeys_;
	delete toolBarMdiConnectTools_;
	delete toolBarFonts_;
	delete menuConnect_; 
	addMainTool();
	updateKeyToolBar();
	loadToolBarPosition();
	if (!windowManager_->activeWindow()) {
		enableMenuToolBar(false);
	} else {
		enableMenuToolBar(true);
		updateMenuToolBar();
	}
	if (FQTermPref::getInstance()->useStyleSheet_) {
		refreshStyleSheet();
	}
}

void FQTermFrame::connectSvr( const std::string& addr , uint16_t port , bool ssh )
{
    if( ssh ){
        __connect_ssh( addr , port );
    }else{
        __connect_telnet( addr , port );
    }
}

void FQTermFrame::__connect_ssh( const std::string& addr , uint16_t port )
{
    FQTermParam param;
    FQTermConfig *pConf = new FQTermConfig(getPath(USER_CONFIG) + "address.cfg");

    loadAddress(pConf, -1, param);
    delete pConf;

    param.port_ = port;
    param.hostAddress_ = addr.c_str();
    param.hostType_ = 1;
    param.protocolType_ = 1;
    param.englishFontSize_ = 12;
    param.otherFontSize_ = 12;
    param.englishFontName_ = "Courier New";
    param.otherFontName_ = "宋体";

    newWindow( param );
}

void FQTermFrame::__connect_telnet( const std::string& addr , uint16_t port )
{
    FQTermParam param;

    FQTermConfig *pConf = new FQTermConfig(getPath(USER_CONFIG) + "address.cfg");

    loadAddress(pConf, -1, param);
    delete pConf;

    param.port_ = port;
    param.hostAddress_ = addr.c_str();
    param.hostType_ = 1;
    param.protocolType_ = 0;
    param.englishFontSize_ = 12;
    param.otherFontSize_ = 12;
    param.englishFontName_ = "Courier New";
    param.otherFontName_ = "宋体";

    newWindow(param);
}

void FQTermFrame::installTranslator(const QString& lang) {
	config_->setItemValue("global", "language", lang);
    QString path = getPath(USER_CONFIG) + "fqterm.cfg";
    if( access( path.toStdString().c_str() , 0 ) < 0 ){
        config_->save( path );
    }

	for (int i = 0; i < translatedModule; ++i) {
		if (translator[i] != 0) {
			qApp->removeTranslator(translator[i]);
			delete translator[i];
			translator[i] = 0;
		}
	}

	if (lang != "en_US" && !lang.isEmpty()) {
		for (int i = 0; i < translatedModule; ++i) {
			QString dict =
				getPath(RESOURCE) + "dict/" + qmPrefix[i] + lang + qmPostfix;
			translator[i] = new QTranslator(0);
			translator[i]->load(dict);
			qApp->installTranslator(translator[i]);
		}
	}

	emit changeLanguage();
}

void FQTermFrame::initTranslator() {
	QString dict_path = getPath(RESOURCE) + "dict/";
	QDir dictDir(dict_path);
	QStringList langList;

	for (int i = 0; i < translatedModule; ++i) {
		translator[i] = 0;
		QStringList filter;
		filter << qmPrefix[i] + "*" + qmPostfix;
		dictDir.setNameFilters(filter);
		QFileInfoList list = dictDir.entryInfoList();

		FQ_TRACE("translator", 3) << "Found " << list.size()
					  <<  "  " << qmPostfix
					  << " file(s) under path "
					  << dict_path;
    
		foreach(QFileInfo info, list){
			QString language = info.fileName();
			language = language.mid(
				qmPrefix[i].length(),
				language.length() - qmPrefix[i].length() - qmPostfix.length());

			FQ_TRACE("translator", 3) << "Check file " << info.fileName();

			if (!langList.contains(language)) {
				langList << language;
				installerList_.append(new TranslatorInstaller(language, this));
				FQ_TRACE("translator", 3) << "Found translations for " << language;
			} else {
				FQ_TRACE("translator", 3) << "Language " << language
							  << " is already registered.";
			}
		}
	}

	if (installerList_.empty()) {
		FQ_TRACE("translator", 0) << "No translations found.";
	}
  
	QString lang = config_->getItemValue("global", "language");
	if (!langList.contains(lang)) {
		lang = QLocale::system().name();
	}
#if defined(__linux__) || defined(__GLIBC__)
	if (QLocale::system().language() == QLocale::English)
		lang = QLocale::system().name();
#endif
	installTranslator(lang);
}


void FQTermFrame::clearTranslator() {
	foreach(TranslatorInstaller* installer, installerList_){
		delete installer;
	}
}

void FQTermFrame::updateLanguageMenu() {
	QString strTmp = config_->getItemValue("global", "language");
	int i = 0;
	foreach(TranslatorInstaller* installer, installerList_){
		if (installer->languageFormalName() == strTmp) {
			languageGroup->actions().at(i + 1)->setChecked(true);
			break;
		}
		++i;
	}
	if (!installerList_.isEmpty() &&
	    (strTmp == "en_US" || i == installerList_.size())) {
		languageGroup->actions().at(0)->setChecked(true);
	}
}

void FQTermFrame::setFont() {
	bool isEnglish = (QAction*)(sender()) == getAction(FQTermShortcutHelper::ENGLISHFONT);
	windowManager_->activeWindow()->setFont(isEnglish);
}

void FQTermFrame::refreshStyleSheet()
{
	qApp->setStyleSheet(qApp->styleSheet());
}
void FQTermFrame::loadStyleSheetFromFile( const QString qssFile )
{
	QFile file(qssFile);
	file.open(QIODevice::ReadOnly);
	QString qss = file.readAll();
	qApp->setStyleSheet(qss);
	file.close();
}

void FQTermFrame::clearStyleSheet() {
	qApp->setStyleSheet("");
}

void FQTermFrame::loadToolBarPosition()
{
	//load toolbar setting
	QString strTmp = config_->getItemValue("global", "toolbarstate");
	if (!strTmp.isEmpty())
	{
		restoreState(QByteArray::fromHex(strTmp.toLatin1()));
	} else {
		addToolBar(Qt::TopToolBarArea, toolBarMdiConnectTools_);
		insertToolBar(toolBarMdiConnectTools_,toolBarSetupKeys_);
		insertToolBar(toolBarSetupKeys_, toolBarMdiTools_);
		insertToolBar(toolBarMdiTools_, toolBarFonts_);
	}
}

void FQTermFrame::toggleAnsiColor() {
	windowManager_->activeWindow()->getSession()->param().isAnsiColor_
		= !windowManager_->activeWindow()->getSession()->param().isAnsiColor_;
	getAction(FQTermShortcutHelper::ANSICOLOR)->setChecked(
		windowManager_->activeWindow()->getSession()->param().isAnsiColor_);
	refreshScreen();
}

bool FQTermFrame::clearUp() {
	if (!windowManager_->closeAllWindow())
		return false;

	saveSetting();
	// clear zmodem and pool if needed
	if (FQTermPref::getInstance()->needClearZmodemPoolOnClose_) {
		clearDir(FQTermPref::getInstance()->zmodemDir_);
		clearDir(FQTermPref::getInstance()->poolDir_);
		clearDir(FQTermPref::getInstance()->poolDir_ + "shadow-cache/");
	}

	setUseDock(false);

	return true;
}

void FQTermFrame::editSchema() {

	schemaDialog schema(this);
	FQ_VERIFY(connect(&schema, SIGNAL(schemaEdited()),
			  this, SLOT(schemaUpdated())));
	schema.exec();
}

void FQTermFrame::schemaUpdated() {
	for (int i = 0; i < windowManager_->count(); ++i) {
		windowManager_->nthWindow(i)->getScreen()->setSchema();
		windowManager_->nthWindow(i)->forcedRepaintScreen();
	}
}

#ifdef USE_GLOBAL_HOTKEY
void FQTermFrame::globalHotkeyTriggered() {
	if (isActiveWindow() && !isMinimized() && isVisible())
	{
		showMinimized();
		return;
	}
	show();
	if (config_->getItemValue("global", "fullscreen") == "1")
		showFullScreen();
	else if (config_->getItemValue("global", "max") == "1")
		showMaximized();
	else 
		showNormal();
	raise();
	activateWindow();
}

void FQTermFrame::globalHotkeyChanged()
{
	globalHotkey_->setShortcut(shortcutHelper_->getAction(FQTermShortcutHelper::GLOBAL_SHOW_FQTERM)->shortcut());
}
#endif //USE_GLOBAL_HOTKEY

TranslatorInstaller::TranslatorInstaller(const QString& language,
                                         FQTermFrame* frame)
	: language_(language),
	  frame_(frame) {
	FQTermConfig conf(getPath(USER_CONFIG) + "language.cfg");

	languageName_ = conf.getItemValue("Name", language_);
	if (languageName_.isEmpty()){
		languageName_ = QLocale::languageToString(QLocale(language_).language());
		if (languageName_ == "C") {
			languageName_ = "Unknown Language";
		}
	}
}

QString TranslatorInstaller::languageName() {
	return languageName_;
}

void TranslatorInstaller::installTranslator() {
	frame_->installTranslator(language_);
}

QString TranslatorInstaller::languageFormalName() {
	return language_;
}

}  // namespace FQTerm

#include "fqterm_frame.moc"
